package fila;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import model.Resultado;
import model.Usuario;
import util.Gerador;

public class CasoAula17 {
	
	private Double lambda;
	private Double mi1;
	private Double mi2;
	
	public CasoAula17(Double lambda, Double mi1, Double mi2) {
		this.lambda = lambda;
		this.mi1 = mi1;
		this.mi2 = mi2;
	}
	
	public Resultado runFCFSFCFSComInterrupcao(int limite) {
		List<Double> amostrasTempo1 = new ArrayList<Double>();
		List<Double> amostrasTempo2 = new ArrayList<Double>();

		Queue<Usuario> fila1 = new LinkedList<Usuario>();
		Queue<Usuario> fila2 = new LinkedList<Usuario>();

        double proximaChegada = Gerador.getExponencial(this.lambda);
        double proximaSaida1 = Double.POSITIVE_INFINITY;
        double proximaSaida2 = Double.POSITIVE_INFINITY;
        
        int index = 0;
        Map<Integer, Double> tempos = new HashMap<Integer, Double>();
        
        while(amostrasTempo2.size() < limite) {
            if (proximaChegada <= proximaSaida1 && proximaChegada <= proximaSaida2) {
            	Usuario novo = new Usuario(index, proximaChegada, Gerador.getExponencial(this.mi1));
 
            	if (fila1.isEmpty() && fila2.isEmpty()) {
                	proximaSaida1 = proximaChegada + novo.getServico();
                } else if(fila1.isEmpty()) {
                	Usuario interrompido = fila2.peek();
	            	interrompido.setServico(proximaSaida2 - proximaChegada);
	            	proximaSaida2 = Double.POSITIVE_INFINITY;
                	proximaSaida1 = proximaChegada + novo.getServico();
                }
 
                fila1.add(novo);
                index++;
                proximaChegada += Gerador.getExponencial(this.lambda);
            } else if(proximaSaida1 <= proximaSaida2) {
            	Usuario antigo = fila1.poll();

                double tempo = proximaSaida1 - antigo.getChegada();
                
                tempos.put(antigo.getIndice(), tempo);
                
                Usuario novo = new Usuario(antigo.getIndice(), proximaSaida1, Gerador.getExponencial(this.mi2));
                
                if (fila2.isEmpty()) {
                	proximaSaida2 = novo.getChegada() + novo.getServico();
                } else {
                	proximaSaida2 = proximaSaida1 + fila2.peek().getServico();
                }
                
                fila2.add(novo);

                if (fila1.isEmpty()) {
                	proximaSaida1 = Double.POSITIVE_INFINITY;
                } else {
                	Double proximoServico = fila1.peek().getServico();
                	proximaSaida1 += proximoServico;
                	
                	if(!fila2.isEmpty()) {
                		proximaSaida2 += proximoServico;
                	}
                }
            } else {
            	Usuario antigo = fila2.poll();

            	double tempo = proximaSaida2 - antigo.getChegada();

                amostrasTempo1.add(tempos.get(antigo.getIndice()));
                amostrasTempo2.add(tempo);
                
                if (fila2.isEmpty())
                	proximaSaida2 = Double.POSITIVE_INFINITY;
                else if (!fila1.isEmpty()) {
                	proximaSaida2 = proximaSaida1 + fila2.peek().getServico();
                } else {
                	proximaSaida2 += fila2.peek().getServico();
                }
            }
        }
        
        return new Resultado(amostrasTempo1, amostrasTempo2);
	}
	
	public Resultado runFCFSFCFSSemInterrupcao(int limite) {
		List<Double> amostrasTempo1 = new ArrayList<Double>();
		List<Double> amostrasTempo2 = new ArrayList<Double>();
		
		Queue<Usuario> fila1 = new LinkedList<Usuario>();
		Queue<Usuario> fila2 = new LinkedList<Usuario>();

        double proximaChegada = Gerador.getExponencial(this.lambda);
        double proximaSaida1 = Double.POSITIVE_INFINITY;
        double proximaSaida2 = Double.POSITIVE_INFINITY;
        
        int index = 0;
        Map<Integer, Double> tempos = new HashMap<Integer, Double>();
        
        while(amostrasTempo2.size() < limite) {
            if (proximaChegada <= proximaSaida1 && proximaChegada <= proximaSaida2) {
            	Usuario novo = new Usuario(index, proximaChegada, Gerador.getExponencial(this.mi1));
            	
                if (fila1.isEmpty() && fila2.isEmpty()) {
                	proximaSaida1 = proximaChegada + novo.getServico();
                } else if(fila1.isEmpty()) {
                	proximaSaida1 = proximaSaida2 + novo.getServico();
                }
 
                fila1.add(novo);
                index++;
                proximaChegada += Gerador.getExponencial(this.lambda);
            } else if(proximaSaida1 <= proximaSaida2) {
            	Usuario antigo = fila1.poll();

                double tempo = proximaSaida1 - antigo.getChegada();
                
                tempos.put(antigo.getIndice(), tempo);
                
                Usuario novo = new Usuario(antigo.getIndice(), proximaSaida1, Gerador.getExponencial(this.mi2));
                
                if (fila2.isEmpty()) {
                	proximaSaida2 = proximaSaida1 + novo.getServico();
                }
                
                fila2.add(novo);

                if (fila1.isEmpty()) {
                	proximaSaida1 = Double.POSITIVE_INFINITY;
                } else {
                	Double proximoServico = fila1.peek().getServico();
                	proximaSaida1 += proximoServico;
                	
                	if(!fila2.isEmpty()) {
                		proximaSaida2 += proximoServico;
                	}
                }
            } else {
            	Usuario antigo = fila2.poll();

            	double tempo = proximaSaida2 - antigo.getChegada();

                amostrasTempo1.add(tempos.get(antigo.getIndice()));
                amostrasTempo2.add(tempo);
                
                if (fila2.isEmpty())
                	proximaSaida2 = Double.POSITIVE_INFINITY;
                else if (!fila1.isEmpty()) {
                	proximaSaida2 = proximaSaida1 + fila2.peek().getServico();
                } else {
                	proximaSaida2 += fila2.peek().getServico();
                }
            }
        }
        
        return new Resultado(amostrasTempo1, amostrasTempo2);
	}

}
